package com.xzzz.common.base.util;

import cn.hutool.core.util.StrUtil;

import javax.management.*;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * JMX 工具类
 *
 * @author xzzz
 * @since 1.0.0
 */
public class JmxUtil {
    private static MBeanServer M_BEAN_SERVER;

    /**
     * EMBEDDED：嵌入式 tomcat
     */
    public static final String EMBEDDED_TOMCAT_SERVER = "Tomcat:type=Server";
    /**
     * STANDALONE：独立的 tomcat
     */
    public static final String STANDALONE_TOMCAT_SERVER = "Catalina:type=Server";

    public static final String EMBEDDED_TOMCAT_CONNECTOR = "Tomcat:type=Connector,port=*";
    public static final String STANDALONE_TOMCAT_CONNECTOR = "Catalina:type=Connector,port=*";

    public static final String EMBEDDED_TOMCAT_GLOBAL_REQUEST_PROCESSOR = "Tomcat:type=GlobalRequestProcessor,name=*";
    public static final String STANDALONE_TOMCAT_GLOBAL_REQUEST_PROCESSOR = "Catalina:type=GlobalRequestProcessor,name=*";

    public static final String EMBEDDED_TOMCAT_PROTOCOL_HANDLER = "Tomcat:type=ProtocolHandler,port=*";
    public static final String STANDALONE_TOMCAT_PROTOCOL_HANDLER = "Catalina:type=ProtocolHandler,port=*";

    public static final String EMBEDDED_TOMCAT_THREAD_POOL = "Tomcat:type=ThreadPool,name=*";
    public static final String STANDALONE_TOMCAT_THREAD_POOL = "Catalina:type=ThreadPool,name=*";

    public static final String EMBEDDED_TOMCAT_SERVLET = "Tomcat:j2eeType=Servlet,WebModule=*,name=dispatcherServlet,J2EEApplication=none,J2EEServer=none";
    public static final String STANDALONE_TOMCAT_SERVLET = "Catalina:j2eeType=Servlet,WebModule=*,name=dispatcherServlet,J2EEApplication=none,J2EEServer=none";

    public static final String EMBEDDED_TOMCAT_STRING_CACHE = "Tomcat:type=StringCache";
    public static final String STANDALONE_TOMCAT_STRING_CACHE = "Catalina:type=StringCache";

    public static final String CUSTOM_SPRING_THREAD_POOL = "Custom:type=ThreadPool,name=spring";
    public static final String CUSTOM_JUC_THREAD_POOL = "Custom:type=ThreadPool,name=juc";
    public static final String CUSTOM_THREAD_POOL = "Custom:type=ThreadPool,name=*";

    public static final String DRUID_DATA_SOURCE = "com.alibaba.druid:type=DruidDataSource,id=*";


    /**
     * 初始化 MBeanServer
     */
    static {
        List<MBeanServer> mBeanServers = MBeanServerFactory.findMBeanServer(null);
        if (!mBeanServers.isEmpty()) {
            M_BEAN_SERVER = mBeanServers.get(0);
        }
        M_BEAN_SERVER = ManagementFactory.getPlatformMBeanServer();
    }

    /**
     * 通过 name 获取 ObjectName【表示一个 MBean 的对象名称，或者可以匹配多个 MBean 名称的模式】
     *
     * @param name 名字【字符串或字符串表达式】
     * @return ObjectName
     */
    private static ObjectName getObjectName(String name) {
        try {
            return new ObjectName(name);
        } catch (MalformedObjectNameException e) {
            throw new RuntimeException("获取 " + name + " 的 ObjectName 对象失败：" + e.getMessage());
        }
    }

    /**
     * 向 MBeanServer 中注册 MBean
     *
     * @param name  名字【字符串或字符串表达式】
     * @param mbean 要注入的 MBean 对象
     */
    public static void register(String name, Object mbean) {
        ObjectName objectName = getObjectName(name);

        try {
            M_BEAN_SERVER.registerMBean(mbean, objectName);
        } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
            throw new RuntimeException("向 MBeanServer 中注册 " + name + " 的 ObjectName 对象失败：" + e.getMessage());
        }
    }

    /**
     * 向 MBeanServer 中注销 MBean
     *
     * @param name 名字【字符串或字符串表达式】
     */
    public static void unregister(String name) {
        ObjectName objectName = getObjectName(name);

        try {
            M_BEAN_SERVER.unregisterMBean(objectName);
        } catch (InstanceNotFoundException | MBeanRegistrationException e) {
            throw new RuntimeException("从 MBeanServer 中注销 " + name + " 的 ObjectName 对象失败：" + e.getMessage());
        }
    }


    /**
     * 获取 ObjectName 集合
     *
     * @param name ObjectName 的 name
     * @return Set<ObjectName>
     */
    public static Set<ObjectName> getObjectNameSet(String name) {
        if (null == M_BEAN_SERVER) {
            return null;
        }
        ObjectName objectName = getObjectName(name);

        return M_BEAN_SERVER.queryNames(objectName, null);
    }

    /**
     * 获取字符串类型的值
     *
     * @param objectName 一个 MBean 的对象名称，或者可以匹配多个 MBean 名称的模式
     * @param key        键
     * @return String
     */
    public static String getMbeanStrVal(ObjectName objectName, String key) {
        if (null == M_BEAN_SERVER || null == objectName || StrUtil.isEmpty(key)) {
            return null;
        }
        try {
            return (String) M_BEAN_SERVER.getAttribute(objectName, key);
        } catch (MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException e) {
            throw new RuntimeException("获取 MBean" + objectName.getKeyProperty("type") + objectName.getKeyProperty("name") + " 中 " + key + "的值失败：" + e.getMessage());
        }
    }

    /**
     * 获取字符串列表类型的值
     *
     * @param objectName 一个 MBean 的对象名称，或者可以匹配多个 MBean 名称的模式
     * @param key        键
     * @return ArrayList<String>
     */
    @SuppressWarnings("unchecked")
    public static ArrayList<String> getMbeanStrArrayListVal(ObjectName objectName, String key) {
        if (null == M_BEAN_SERVER || null == objectName || StrUtil.isEmpty(key)) {
            return null;
        }
        try {
            return (ArrayList<String>) M_BEAN_SERVER.getAttribute(objectName, key);
        } catch (MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException e) {
            throw new RuntimeException("获取 MBean" + objectName.getKeyProperty("type") + objectName.getKeyProperty("name") + " 中 " + key + "的值失败：" + e.getMessage());
        }
    }

    /**
     * 获取 Integer 类型的值
     *
     * @param objectName 一个 MBean 的对象名称，或者可以匹配多个 MBean 名称的模式
     * @param key        键
     * @return Integer
     */
    public static Integer getMbeanIntegerVal(ObjectName objectName, String key) {
        if (null == M_BEAN_SERVER || null == objectName || StrUtil.isEmpty(key)) {
            return null;
        }
        try {
            return (Integer) M_BEAN_SERVER.getAttribute(objectName, key);
        } catch (MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException e) {
            throw new RuntimeException("获取 MBean" + objectName.getKeyProperty("type") + objectName.getKeyProperty("name") + " 中 " + key + "的值失败：" + e.getMessage());
        }
    }

    /**
     * 获取 Long 类型的值
     *
     * @param objectName 一个 MBean 的对象名称，或者可以匹配多个 MBean 名称的模式
     * @param key        键
     * @return Long
     */
    public static Long getMbeanLongVal(ObjectName objectName, String key) {
        if (null == M_BEAN_SERVER || null == objectName || StrUtil.isEmpty(key)) {
            return null;
        }
        try {
            return (Long) M_BEAN_SERVER.getAttribute(objectName, key);
        } catch (MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException e) {
            throw new RuntimeException("获取 MBean" + objectName.getKeyProperty("type") + objectName.getKeyProperty("name") + " 中 " + key + "的值失败：" + e.getMessage());
        }
    }

    /**
     * 获取 long[] 类型的值
     *
     * @param objectName 一个 MBean 的对象名称，或者可以匹配多个 MBean 名称的模式
     * @param key        键
     * @return long[]
     */
    public static long[] getMbeanLongArrVal(ObjectName objectName, String key) {
        if (null == M_BEAN_SERVER || null == objectName || StrUtil.isEmpty(key)) {
            return null;
        }
        try {
            return (long[]) M_BEAN_SERVER.getAttribute(objectName, key);
        } catch (MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException e) {
            throw new RuntimeException("获取 MBean" + objectName.getKeyProperty("type") + objectName.getKeyProperty("name") + " 中 " + key + "的值失败：" + e.getMessage());
        }
    }

    /**
     * 获取 Boolean 类型的值
     *
     * @param objectName 一个 MBean 的对象名称，或者可以匹配多个 MBean 名称的模式
     * @param key        键
     * @return Boolean
     */
    public static Boolean getMbeanBooleanVal(ObjectName objectName, String key) {
        if (null == M_BEAN_SERVER || null == objectName || StrUtil.isEmpty(key)) {
            return null;
        }
        try {
            return (Boolean) M_BEAN_SERVER.getAttribute(objectName, key);
        } catch (MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException e) {
            throw new RuntimeException("获取 MBean" + objectName.getKeyProperty("type") + objectName.getKeyProperty("name") + " 中 " + key + "的值失败：" + e.getMessage());
        }
    }


    /**
     * 获取 Date 类型的值
     *
     * @param objectName 一个 MBean 的对象名称，或者可以匹配多个 MBean 名称的模式
     * @param key        键
     * @return Date
     */
    public static Date getMbeanDateVal(ObjectName objectName, String key) {
        if (null == M_BEAN_SERVER || null == objectName || StrUtil.isEmpty(key)) {
            return null;
        }
        try {
            return (Date) M_BEAN_SERVER.getAttribute(objectName, key);
        } catch (MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException e) {
            throw new RuntimeException("获取 MBean" + objectName.getKeyProperty("type") + objectName.getKeyProperty("name") + " 中 " + key + "的值失败：" + e.getMessage());
        }
    }
}
